package org.jrfe.sys;

import org.jrfe.sys.input.KeyEvent;
import org.jrfe.sys.input.KeyListener;
import org.jrfe.sys.input.MouseEvent;
import org.jrfe.sys.input.MouseListener;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;

public abstract class JRFEInput {

	protected static Key[] keys;
	protected static MouseKey[] mouseKey;

	protected static KeyListener keyListener;
	protected static MouseListener mouseListener;

	protected static int mouseX = 0;
	protected static int mouseY = 0;
	protected static int mouseDeltaX = 0;
	protected static int mouseDeltaY = 0;

	protected static boolean moved = false;

	public static boolean initilize() {
		try {
			Keyboard.create();
		} catch (LWJGLException e) {
			e.printStackTrace();
			Sys.alert("Keyboard Error", "Keybord can't be crated");
			return false;
		}

		try {
			Mouse.create();
		} catch (LWJGLException e) {
			e.printStackTrace();
			Sys.alert("Mouse Error", "Mouse can't be crated");
			return false;
		}

		keys = new Key[224];
		System.out.println(Mouse.getButtonCount());
		mouseKey = new MouseKey[Mouse.getButtonCount()];

		for (int i = 0; i < mouseKey.length; i++) {
			mouseKey[i] = new MouseKey();
		}

		for (int i = 0; i < keys.length; i++) {
			keys[i] = new Key();
		}

		return true;
	}

	public void destroy() {
		Keyboard.destroy();
		Mouse.destroy();
	}

	public static void setKeyListener(KeyListener listener) {
		keyListener = listener;
	}

	public static void setMouseListener(MouseListener listener) {
		mouseListener = listener;
	}

	public static void capture() {
		captureKeys();
		captureMouse();
	}

	public static void captureKeys() {
		Keyboard.poll();
		Key k;
		while (Keyboard.next()) {
			k = keys[Keyboard.getEventKey()];
			k.chr = Keyboard.getEventCharacter();

			if (Keyboard.getEventKeyState()) {
				k.pressed = true;
			} else {
				k.released = true;
			}
		}
	}

	public static void captureMouse() {
		Mouse.poll();

		while (Mouse.next()) {
			if (Mouse.getEventButton() != -1) {
				MouseKey key = mouseKey[Mouse.getEventButton()];
				if (Mouse.getEventButtonState()) {
					key.pressed = true;
				} else {
					key.released = true;
				}
			}
		}

		int x = Mouse.getX();
		int y = Mouse.getY();

		if (x != mouseX || y != mouseY) {
			mouseDeltaX = x - mouseX;
			mouseDeltaY = y - mouseY;

			mouseX = x;
			mouseY = y;
			moved = true;
		}

	}

	public static void process() {
		processKeys();
		processMouse();
	}

	public static void processKeys() {
		KeyEvent event = new KeyEvent();
		for (int i = 0; i < keys.length; i++) {

			Key key = keys[i];

			if (key.pressed && key.released) {

				key.pressed = false;
				key.repeated = false;
				key.released = false;

				event.keycode = i;
				event.chr = key.chr;

				if (!key.procesed) {
					keyListener.keyPressed(event);
					keyListener.keyTyped(event);
				}

				key.procesed = false;

				keyListener.keyReleased(event);

			} else if (key.pressed) {
				event.keycode = i;
				event.chr = key.chr;
				if (key.repeated) {
					keyListener.keyTyped(event);
				} else {
					keyListener.keyPressed(event);
					keyListener.keyTyped(event);
					key.repeated = true;
					key.procesed = true;
				}
			}

			// This is straight port form c++ so need to test this code with
			// jinput
			// This is to fix strange effects for keys
			// When some key events are missed usually by low frame rate
			if (key.released) {
				if (!key.pressed) {
					key.pressed = false;
					key.repeated = false;
					key.released = false;
					key.procesed = false;
				}
			}

		}
	}

	public static void processMouse() {
		MouseEvent event = new MouseEvent();
		event.mouseX = mouseX;
		event.mouseY = mouseY;
		event.mouseDeltaX = mouseDeltaX;
		event.mouseDeltaY = mouseDeltaY;

		if (moved) {
			moved = false;
			mouseListener.mouseMoved(event);
		}

		for (int i = 0; i < mouseKey.length; i++) {
			MouseKey key = mouseKey[i];
			if (key.pressed && key.released) {
				key.pressed = false;
				key.repeated = false;
				key.released = false;

				event.key = i;
				mouseListener.mouseReleased(event);
			} else if (key.pressed) {
				if (key.repeated) {

				} else {
					event.key = i;
					mouseListener.mousePressed(event);
					key.repeated = true;
				}
			}
		}
	}

	public static boolean isKeyDownHW(int keycode) {
		return Keyboard.isKeyDown(keycode);
	}

	public static boolean isKeyDown(int keycode) {
		return keys[keycode].pressed;
	}

}

class Key {
	public boolean pressed = false;
	public boolean released = false;
	public boolean repeated = false;
	public boolean procesed = false;
	public char chr;
}

class MouseKey {
	public boolean pressed = false;
	public boolean repeated = false;
	public boolean released = false;
}